<?php

/**
 * Contains "Ajax" request handler class.
 *
 * LICENSE: MIT
 *
 * @author Peter Pippinger
 * @category PP
 * @package PP_Ajax
 * @copyright Copyright (c) 2015 Peter Pippinger
 * @license http://opensource.org/licenses/MIT
 * @version 1.1.0
 * @since Class exists since release 1.0.0
 */

/**
 * "Ajax" request handler class.
 *
 * Provides handling of ajax requests and output for client side javascript.
 *
 * @author Peter Pippinger
 * @category PP
 * @package PP_Ajax
 * @copyright Copyright (c) 2015 Peter Pippinger
 * @license http://opensource.org/licenses/MIT
 * @version 1.1.0
 * @since Class exists since release 1.0.0
 */
class Ajax
{

	/**
	 * Contains the "Ajax" object instance for singleton.
	 *
	 * @var Object
	 */
	private static $_ajaxObj = null;

	/**
	 * Counts stored responses.
	 *
	 * @var Integer
	 */
	private static $_responseCount = - 1;

	/**
	 * Stores responses.
	 *
	 * @var Array
	 */
	private static $_responses = array();

	/**
	 * Handles gets on non existing class members for fluent interface.
	 *
	 * @param $name member
	 *        	name
	 * @return Object "Ajax" object for fluent interface
	 */
	function __get($name)
	{
		Ajax::$_responses[Ajax::$_responseCount][] = $name;
		return $this;
	}

	/**
	 * Handles sets on non existing class members for fluent interface.
	 *
	 * @param $name member
	 *        	name
	 * @param $value value
	 *        	to set
	 */
	function __set($name, $value)
	{
		$value = json_encode($value);
		Ajax::$_responses[Ajax::$_responseCount][] = $name . "=" . $value;
	}

	/**
	 * Handles requests on non existing methods for fluent interface.
	 *
	 * @param $name method
	 *        	name
	 * @param $arguments arguments
	 *        	given to method
	 * @return Object "Ajax" object for fluent interface
	 */
	function __call($name, $arguments)
	{
		foreach ($arguments as $argumentNumber => $argument) {
			$arguments[$argumentNumber] = json_encode($argument);
		}
		Ajax::$_responses[Ajax::$_responseCount][] = $name . "(" . implode(",", $arguments) . ")";
		return $this;
	}

	/**
	 * Adds a response to be send to the client.
	 * This is the first
	 * method in the fluent interface chain.
	 *
	 * @return Object "Ajax" object for fluent interface
	 */
	public static function addResponse()
	{
		Ajax::$_responseCount ++;
		Ajax::$_responses[Ajax::$_responseCount] = array();
		if (is_a(Ajax::$_ajaxObj, "Ajax")) {
			return Ajax::$_ajaxObj;
		} else {
			Ajax::$_ajaxObj = new Ajax();
			return Ajax::$_ajaxObj;
		}
	}

	/**
	 * Outputs needed client side javascript for ajax requests.
	 *
	 * @param
	 *        	<p>$ajaxDebugLevel Integer</p>
	 *        	<p>0 = Show no response errors and no response code.</p>
	 *        	<p>1 = Show response errors but no response code.</p>
	 *        	<p>2 = Show response errors and response code.</p>
	 */
	public static function outputJs($ajaxDebugLevel = 0)
	{
		echo '<script>' . PHP_EOL . '			function php(){$.ajax({async:arguments[0]=="async",type:"POST",url:"' . $_SERVER["REQUEST_URI"] . '",' . PHP_EOL . '			data:{ajaxRequest:true,arguments:JSON.stringify(arguments)}}).done(' . PHP_EOL . '			function(response){' . ($ajaxDebugLevel > 1 ? 'alert("Response is:\n"+' . 'response.replace(/(<([^>]+)>)/ig,""));' : '') . 'try{eval(response);}catch(e){' . ($ajaxDebugLevel > 0 ? 'alert(e+"\n\nResponse was:\n"+response);' : '') . '}});}' . PHP_EOL . '			function phpResponse(){return $.ajax({async:arguments[0]=="async",type:"POST",url:"' . $_SERVER["REQUEST_URI"] . '",' . PHP_EOL . '			data:{ajaxRequest:true,arguments:JSON.stringify(arguments)}}).responseText;}' . PHP_EOL . '		</script>' . PHP_EOL;
	}

	/**
	 * Executes the ajax request sent by the client and
	 * outputs the response for the client.
	 * Notice: PHP processing ends after the response.
	 */
	public static function executeRequest()
	{
		if (isset($_POST["ajaxRequest"])) {
			$requestArguments = json_decode($_POST["arguments"], true);
			array_shift($requestArguments);
			$ajaxFunctionParts = explode("/", array_shift($requestArguments));
			$ajaxFunctionDir = $ajaxFunctionParts[0];
			$ajaxFunctionName = "ajax_" . $ajaxFunctionParts[1];
			require_once ROOT_PATH . "/Lib/Mvc/Modules/$ajaxFunctionDir/ajaxFunctions.php";
			
			if (function_exists($ajaxFunctionName)) {
				call_user_func_array($ajaxFunctionName, $requestArguments);
			} else {
				Ajax::addResponse()->alert("PHP function \"$ajaxFunctionName\" not found error.");
			}
			$responseJs = "";
			foreach (Ajax::$_responses as $responseNumber => $responsePieces) {
				$responseJs .= implode(".", $responsePieces) . ";" . PHP_EOL;
			}
			echo ($responseJs);
			die();
		}
	}
}